package org.wevil.util;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;

/**
 * RSA工具类。非对称算法
 *
 * @author wevil
 * @since 2023/9/25
 */
public class RSAUtil {

    /**
     * RSA是一种非对称加密算法，ECB是一种分组密码模式，PKCS1Padding是一种填充方式，它使用PKCS#1 v1.5标准来填充数据。
     */
    private static final String ALGORITHM = "RSA/ECB/PKCS1Padding";

    /**
     * 密钥长度，DH算法的默认密钥长度是1024
     * 密钥长度必须是64的倍数，在512到65536位之间。
     * 一般常用的是1024，2048，2096，长度越长生成时间越长
     */
    final private static int KEY_SIZE = 512;

    /**
     * 生成一对新的公钥和私钥 KeyPair
     */
    public static KeyPair genKeyPair() throws NoSuchAlgorithmException {
        final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(KEY_SIZE, new SecureRandom());
        return keyGen.generateKeyPair();
    }

    /**
     * RSA加密 公钥加密
     *
     * @param str 字符
     * @param key 公钥
     * @author wanglei
     * @since 2023/9/25
     */
    public static String encrypt(String str, PublicKey key) throws NoSuchPaddingException, NoSuchAlgorithmException,
            IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        byte[] cipherText = null;
        final Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        cipherText = cipher.doFinal(str.getBytes());
        return Base64.encodeBase64String(cipherText);
    }

    /**
     * RSA解密 私钥解密
     *
     * @param str 密文
     * @param key 私钥
     * @author wanglei
     * @since 2023/9/25
     */
    public static String decrypt(String str, PrivateKey key) throws NoSuchPaddingException,
            NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
        byte[] decryptText;
        final Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        decryptText = cipher.doFinal(Base64.decodeBase64(str));
        return new String(decryptText);
    }
}
